﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "ALSoundSystem.h"

namespace UX_STL
{
namespace ALShell
{

#ifdef _UXS_STL_CONFIGURATION_H
	ALSoundSystem	*_s_pSoundSys = null;
#endif


/*
=================================================
	конструктор
=================================================
*/
	ALSoundSystem::ALSoundSystem():
		_pDevice(null), _pContext(null), _bPause(false),
		_uMaxAuxSends(0), _uEfxVersion(0)
	{
		
		// init global variables
#	ifdef _UXS_STL_CONFIGURATION_H
		ASSERT( _s_pSoundSys == null );
		_s_pSoundSys = this;
#	endif
	}

/*
=================================================
	деструктор
=================================================
*/
	ALSoundSystem::~ALSoundSystem()
	{
		alcMakeContextCurrent( null );

		if ( _pContext != null )
			alcDestroyContext( _pContext );

		if ( _pDevice != null )
			alcCloseDevice( _pDevice );

		CHECK( AL_Delete() );
		
#	ifdef _UXS_STL_CONFIGURATION_H
		ASSERT( _s_pSoundSys == this );
		_s_pSoundSys = null;
#	endif
	}

/*
=================================================
	инициализация OpenAL
=================================================
*/
	bool ALSoundSystem::Init(uni_c_string pAudioDevice, uint uAUXSlots)
	{
		char	res = AL_Init();

		if ( res != 0 )
		{
			LOG( "Error(s) while initialize OpenAL.", e_log_msg::WARNING_NL_4 );

			const char	*p_error = AL_GetError();

			while ( p_error != null )
			{
				LOG( p_error, e_log_msg::ERROR_NL_4 );
				p_error = AL_GetError();
			}

			AL_ClearErrors();

			if ( res == 2 )
				RETURN_ERR( "Critical error while init OpenAL" );
		}

		_pDevice = alcOpenDevice( pAudioDevice.Empty() ? "" : pAudioDevice.cstr() );

		if ( _pDevice == null and not pAudioDevice.Empty() )
		{
			LOG( (string("Can't create a \"") << pAudioDevice << "\" device. Try to open default audio device.").cstr(), e_log_msg::WARNING_3 );
			_pDevice = alcOpenDevice( null );
		}

		if ( _pDevice == null ) {
			LOG( "Can't create OpenAL device.", e_log_msg::ERROR_2 );
			return false;
		}
		

		const ALCint	a_attrlist[] = {
									ALC_MAX_AUXILIARY_SENDS, uAUXSlots,
									0, 0 };

		_pContext = alcCreateContext( _pDevice, a_attrlist );
		
		if ( _pContext == null ) {
			LOG( "Can't create OpenAL context.", e_log_msg::ERROR_2 );
			return false;
		}
		
		if ( alcMakeContextCurrent( _pContext ) != AL_TRUE ) {
			LOG( "Can't make context current.", e_log_msg::ERROR_2 );
			return false;
		}

		bool	ext_inited = AL_InitExtensions( _pDevice );

		if ( !ext_inited )
		{
			LOG( "Error(s) while initialize OpenAL extensions.", e_log_msg::WARNING_NL_4 );

			const char	*p_error = AL_GetError();

			while ( p_error != null )
			{
				LOG( p_error, e_log_msg::ERROR_NL_4 );
				p_error = AL_GetError();
			}

			AL_ClearErrors();
		}

		ALCint	i_min_ver	= 0,
				i_maj_ver	= 0,
				i_max_sends	= 0;

		
		ALC_CALL( alcGetIntegerv( _pDevice, ALC_MAX_AUXILIARY_SENDS, 1, &i_max_sends ) );
		ALC_CALL( alcGetIntegerv( _pDevice, ALC_EFX_MAJOR_VERSION,   1, &i_maj_ver ) );
		ALC_CALL( alcGetIntegerv( _pDevice, ALC_EFX_MAJOR_VERSION,   1, &i_min_ver ) );

		_uEfxVersion  = i_maj_ver * 100 + i_min_ver * 10;
		_uMaxAuxSends = i_max_sends;
		return true;
	}
	
/*
=================================================
	записывает в лог информацию о OpenAL
=================================================
*/
	void ALSoundSystem::GetOpenALInfo(string &sInfo) const
	{
		if ( _pContext == null or _pDevice == null )
			return;

		sInfo << "---------------\nOpenAL info\n---------------"
			  << "\nVersion:   " << (const char *)alGetString( AL_VERSION )
			  << "\nVendor:    " << (const char *)alGetString( AL_VENDOR )
			  << "\nDevice:    " << (const char *)alcGetString( _pDevice, ALC_DEVICE_SPECIFIER )
			  << '\n';
	}

//-------------------------------------------------------------------

}	// ALShell
}	// UX_STL